package fun.ipconfig.utils;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;


/**
 * Description: excel 转实体
 *
 * @author: gtinlian
 * @date: 2023/12/6
 * @version: v2.0.1.62
 */
public class ExcelParseUtils<T> {
    private static Logger logger = LoggerFactory.getLogger(ExcelParseUtils.class);
    private Workbook work;  // 表格对象
    private Sheet sheet; // 设置表
    private Integer startRaw;  // 开始解析行
    private Boolean headerCheck; // 头部校验
    
    private ExcelParseUtils(Workbook workbook) {
        try {
            sheet = null;
            startRaw = null;
            headerCheck = true;
            work = workbook;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 文件解析 Excel 2007 之后版本的表格解析
     * @param in
     * @param <T>
     * @return
     * @throws IOException
     */
    public static <T> ExcelParseUtils<T> getInstanceXlsx(InputStream in) throws IOException {
        SXSSFWorkbook work = new SXSSFWorkbook(new XSSFWorkbook(in));
        work.setCompressTempFiles(true);
        return new ExcelParseUtils<T>(work);
    }

    /**
     * 文件解析 Excel 2003 之前版本的表格解析
     *
     * @param in
     * @param <T>
     * @return
     * @throws IOException
     */
    public static <T> ExcelParseUtils<T> getInstanceXls(InputStream in) throws IOException {
        Workbook work = new HSSFWorkbook(in,false);
        return new ExcelParseUtils<T>(work);
    }
    
    /**
     * Description: 指定列的数据处理接口
     *
     * @author: gtinlian
     * @date: 2023/12/7
     * @version: v2.0.1.62
     */
    public interface MapperFieldStr {
        void set(String t);
    }

    /**
     * Description: 指定列的数据处理接口
     *
     * @author: gtinlian
     * @date: 2023/12/7
     * @version: v2.0.1.62
     */
    public interface MapperFieldCell<T extends Cell> {
        void set(T t);
    }

    /**
     * Description: 实现实体对象和表格对应列的映射实现
     *
     * @param <T>
     * @author: gtinlian
     * @date: 2023/12/7
     * @version: v2.0.1.62
     */
    public interface RawMapperFieldStr<T> {
        MapperFieldStr[] getHeader(T t);
    }

    /**
     * Description: 实现实体对象和表格对应列的映射实现
     *
     * @param <T>
     * @author: gtinlian
     * @date: 2023/12/7
     * @version: v2.0.1.62
     */
    public interface RawMapperFieldCell<T> {
        MapperFieldCell[] getHeader(T t);
    }
    
    /**
     * Description: 指定要解析的工作表
     *
     * @param sheetName
     * @return
     * @author: gtinlian
     * @date: 2023/12/7
     * @version: v2.0.1.62
     */
    public ExcelParseUtils<T> parseSheet(String sheetName) {
        sheet = work.getSheet(sheetName);
        return this;
    }

    /**
     * Description: 指定要解析的工作表
     *
     * @param sheetIndex
     * @return
     * @author: gtinlian
     * @date: 2023/12/7
     * @version: v2.0.1.62
     */
    public ExcelParseUtils<T> parseSheet(int sheetIndex) {
        if(work instanceof SXSSFWorkbook)
            sheet = ((SXSSFWorkbook)work).getXSSFWorkbook().getSheetAt(sheetIndex);
        else
            sheet = work.getSheetAt(sheetIndex);
        return this;
    }

    /**
     * Description: 设置工作表开始解析行
     *
     * @param startRaw
     * @return
     * @author: gtinlian
     * @date: 2023/12/7
     * @version: v2.0.1.62
     */
    public ExcelParseUtils<T> parseStartRaw(int startRaw) {
        this.startRaw = startRaw;
        return this;
    }

    /**
     * Description: 获取实体列表
     *
     * @param tClass
     * @param mapper
     * @return
     * @author: gtinlian
     * @date: 2023/12/7
     * @version: v2.0.1.62
     */
    public List<T> getEntityByStrInvoke(Class<T> tClass, RawMapperFieldStr<T> mapper) {
        List<T> list = new LinkedList<>();
        if (!headerCheck) {
            logger.error("头部检查不通过"); headerCheck = !headerCheck; next(); return list;
        }
        try {
            if (sheet != null || startRaw != null) {
                while (true) {
                    T obj = tClass.newInstance();
                    MapperFieldStr[] setField = mapper.getHeader(obj);
                    Row row = sheet.getRow(startRaw);
                    startRaw++;
                    boolean end = true;
                    for (int i = 0; i < setField.length; i++) {
                        if (row == null) {
                            break;
                        }
                        if (setField[i] == null) continue;
                        Cell cell = row.getCell(i);
                        String value =  null;
                        if(cell instanceof  XSSFCell){
                             value = ((XSSFCell)cell).getCTCell().getV();
                        }else {
                            cell.setCellType(1); value = cell.getStringCellValue();
                        }
                        if (value != null) end = false;
                        setField[i].set(value);
                    }
                    if (end) break;
                    list.add(obj);
                }
            } else {
                if (sheet == null)
                    logger.error("将excel转实体时必须先调用parseSheet([index:int|name:str])");
                if (startRaw == null)
                    logger.error("将excel转实体时必须先调用parseStartRaw(startRaw)指定开始行");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            next();
        }
        return list;
    }

    /**
     * Description: 获取实体列表
     *
     * @param tClass
     * @param mapper
     * @return
     * @author: gtinlian
     * @date: 2023/12/7
     * @version: v2.0.1.62
     */
    public List<T> getEntityByCellInvoke(Class<T> tClass, RawMapperFieldCell<T> mapper) {
        List<T> list = new LinkedList<>();
        if (!headerCheck) { 
            logger.error("头部检查不通过"); headerCheck = !headerCheck; next(); return list;
        }
        try {
            if (sheet != null || startRaw != null) {
                while (true) {
                    T obj = tClass.newInstance();
                    MapperFieldCell[] setField = mapper.getHeader(obj);
                    Row row = sheet.getRow(startRaw);
                    startRaw++;
                    boolean end = true;
                    for (int i = 0; i < setField.length; i++) {
                        if (row == null) 
                            break;
                        if (setField[i] == null) continue;
                        Cell value = row.getCell(i);
                        if (value != null) {
                            end = false;
                            setField[i].set(value);
                        }
                    }
                    if (end) break;
                    list.add(obj);
                }
            } else {
                if (sheet == null)
                    logger.error("将excel转实体时必须先调用parseSheet([index:int|name:str])");
                if (startRaw == null)
                    logger.error("将excel转实体时必须先调用parseStartRaw(startRaw)指定开始行");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            next();
        }
        return list;
    }

    /**
     *  Description: 头部检查
     * @author: gtinlian
     * @date: 2023/12/18
     * @version: v2.0.1.62
     * @param checkRaw
     * @param check
     * @return
     */
    public ExcelParseUtils<T> checkHeaderIn(int checkRaw, String[] check) {
        Row row = sheet.getRow(checkRaw);
        for (int i = 0; i < check.length; i++) {
            if (check[i] == null) continue;
            Cell cell = row.getCell(i); 
            String value = null;
            if(!(cell instanceof XSSFCell)) { 
                cell.setCellType(Cell.CELL_TYPE_STRING);value = cell.getStringCellValue(); 
            } else { 
                value = ((XSSFCell) cell).getCTCell().getV(); 
            }
            if (!check[i].equals(value)) { headerCheck = false;return this; }
        }
        return this;
    }
    
    /**
     *  Description: 关闭对象
     * @author: gtinlian
     * @date: 2023/12/18
     * @version: v2.0.1.62
     */
    public void close() {
        if (work != null) {
            try {
                work.close();
            } catch (Exception e) {
            } finally {
                work = null;
            }
        }
    }

    /**
     *  Description: 重置服务
     * @author: gtinlian
     * @date: 2023/12/18
     * @version: v2.0.1.62
     */
    public void next() {
        sheet = null;
        startRaw = null;
        headerCheck = true;
    }
    
    @Override
    protected void finalize() throws Throwable {
        close();
        super.finalize();
    }
}
